﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.Contracts;

namespace GBricks.Collections
{
  [Serializable]
  public class ReadOnlyOrderedDictionary<TKey, TValue> : ReadOnlyDictionary<TKey, TValue>, IReadOnlyOrderedDictionary<TKey, TValue>
  {
    private static readonly ReadOnlyOrderedDictionary<TKey, TValue> EmptyInstance = new ReadOnlyOrderedDictionary<TKey, TValue>(new OrderedDictionary<TKey, TValue>());

    public ReadOnlyOrderedDictionary(IOrderedDictionary<TKey, TValue> dictionary)
      : base(dictionary) {
        Contract.Assume(Dictionary.Count == Count);
    }

    public static ReadOnlyOrderedDictionary<TKey, TValue> Empty {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<ReadOnlyOrderedDictionary<TKey, TValue>>() != null);
        return EmptyInstance;
      }
    }

    protected new IOrderedDictionary<TKey, TValue> Dictionary {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<IOrderedDictionary<TKey, TValue>>() != null);
        return (IOrderedDictionary<TKey, TValue>)base.Dictionary;
      }
    }

    [ContractInvariantMethod]
    private void Invariant() {
      Contract.Invariant(Dictionary != null);
      Contract.Invariant(base.Dictionary is IOrderedDictionary<TKey, TValue>);
      Contract.Invariant(Dictionary.Count == Count);
      Contract.Invariant(Dictionary.Keys.Count == Count);
      Contract.Invariant(Dictionary.Values.Count == Count);
    }

    #region IReadOnlyOrderedDictionary<TKey, TValue> Members

    public new IReadOnlyList<TKey> Keys {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<IReadOnlyList<TKey>>() != null);
        Contract.Ensures(Contract.Result<IReadOnlyList<TKey>>().Count == Count);
        return Dictionary.Keys;
      }
    }

    public new IReadOnlyList<TValue> Values {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<IReadOnlyList<TValue>>() != null);
        Contract.Ensures(Contract.Result<IReadOnlyList<TValue>>().Count == Count);
        return Dictionary.Values;
      }
    }

    public int IndexOf(TKey key) {
      Contract.Ensures(Contract.Result<int>() >= -1);
      Contract.Ensures(Contract.Result<int>() < Count);
      return Dictionary.IndexOf(key);
    }

    #endregion IReadOnlyOrderedDictionary<TKey, TValue> Members

    #region IReadOnlyList<KeyValuePair<TKey, TValue>> Members

    public KeyValuePair<TKey, TValue> this[int index] {
      [DebuggerStepThrough]
      get {
        Argument.OutOfRange(index >= 0, index, "index");
        Argument.OutOfRange(index < Count, index, "index");
        return Dictionary[index];
      }
    }

    #endregion IReadOnlyList<KeyValuePair<TKey, TValue>> Members
  }
}
